package model

import (
	. "alarmservice/proconfig"
	"errors"
	"reflect"
	"strconv"

	"github.com/astaxie/beego"
	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"
)

var Orm *xorm.Engine
var orm *xorm.Engine

var ErrNotExist error

const (
	StatusNormal  = 10
	StatusDeleted = -10
)

type IdList []int64

func Init() {
	//初始化变量
	ErrNotExist = errors.New("not exist")

	//初始化引擎
	//获取配置信息 db section
	dbSection, err := Config.GetSection("db")
	if err != nil {
		panic("db config not set!" + err.Error())
	}

	host, hostOk := dbSection["host"]
	username, usernameOk := dbSection["username"]
	password, passwordOk := dbSection["password"]
	database, databaseOk := dbSection["database"]
	charset, charsetOk := dbSection["charset"]

	if !hostOk || !usernameOk || !passwordOk || !databaseOk {
		panic("please set host,username,password,database config")
	}

	if !charsetOk {
		charset = "utf8"
	}

	//dsn格式 "root:123@/test?charset=utf8"
	Orm, err = xorm.NewEngine("mysql", username+":"+password+"@tcp("+host+")/"+database+"?"+charset)
	if err != nil {
		panic("init mysql engine error")
	}

	logger := NewLogger(beego.BeeLogger)
	Orm.ShowSQL(true)
	Orm.SetLogger(logger)

	orm = Orm
}

func GetById(id int64, obj interface{}) error {
	has, err := orm.Id(id).Get(obj)
	if err != nil {
		return err
	}
	if !has {
		return ErrNotExist
	}
	return nil
}

func GetByExample(obj interface{}) error {
	has, err := orm.Get(obj)
	if err != nil {
		return err
	}
	if !has {
		return ErrNotExist
	}
	return nil
}

func CountByExample(obj interface{}) (int64, error) {
	return orm.Count(obj)
}

func Count(obj interface{}) (int64, error) {
	return orm.Count(obj)
}

func IsExist(obj interface{}) bool {
	has, _ := orm.Get(obj)
	return has
}

func Insert(obj interface{}) error {
	_, err := orm.Insert(obj)
	return err
}

func Find(limit, start int, objs interface{}) error {
	return orm.Limit(limit, start).Find(objs)
}

func DeleteById(id int64, obj interface{}) error {
	_, err := orm.Id(id).Delete(obj)
	return err
}

func DeleteByExample(obj interface{}) error {
	_, err := orm.Delete(obj)
	return err
}

func Obj2Table(objs []string) []string {
	var res = make([]string, len(objs))
	for i, c := range objs {
		res[i] = orm.ColumnMapper.Obj2Table(c)
	}
	return res
}

func Obj2Map(obj interface{}) map[string]interface{} {
	vv := reflect.ValueOf(obj)

	if vv.Kind() == reflect.Ptr && !vv.IsNil() {
		vv = vv.Elem()
	}

	vt := vv.Type()

	m := make(map[string]interface{})
	for i := 0; i < vt.NumField(); i++ {
		f := vt.Field(i)
		fName := f.Name
		m[fName] = vv.FieldByIndex(f.Index).Interface()
	}

	return m
}

func UpdateById(id int64, object interface{}, cols ...string) error {
	_, err := orm.Cols(cols...).Id(id).Update(object)
	return err
}

//如果是非整形数字类型，将忽略
func MapIntKeyToStr(m interface{}) map[string]interface{} {
	v := reflect.ValueOf(m)
	t := reflect.TypeOf(m)

	if t.Kind() != reflect.Map {
		panic("MapIntKeyToStr need map[int]")
	}

	keys := v.MapKeys()

	ret := make(map[string]interface{})

	if len(keys) == 0 {
		return ret
	}

	isInt := false

	switch keys[0].Interface().(type) {
	case int, int8, int16, int32, int64:
		isInt = true
	}

	if !isInt {
		panic("MapIntKeyToStr need map[int]")
	}

	for _, k := range keys {
		kStr := strconv.FormatInt(k.Int(), 10)
		ret[kStr] = v.MapIndex(k).Interface()
	}

	return ret
}

func (list IdList) Swap(i, j int) {
	list[i], list[j] = list[j], list[i]
}

func (list IdList) Less(i, j int) bool {
	return list[i] < list[j]
}

func (list IdList) Len() int {
	return len(list)
}
